home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / sbin / deluser < prev    next >
Text File  |  2009-08-03  |  16KB  |  528 lines

  1. #!/usr/bin/perl
  2.  
  3. # deluser -- a utility to remove users from the system
  4. # delgroup -- a utilty to remove groups from the system
  5. my $version = "3.110ubuntu6";
  6.  
  7. # Copyright (C) 2000 Roland Bauerschmidt <rb@debian.org>
  8. # Based on 'adduser' as pattern by
  9. #     Guy Maor <maor@debian.org>
  10. #     Ted Hajek <tedhajek@boombox.micro.umn.edu>
  11. #     Ian A. Murdock <imurdock@gnu.ai.mit.edu>
  12.  
  13. # This program is free software; you can redistribute it and/or modify
  14. # it under the terms of the GNU General Public License as published by
  15. # the Free Software Foundation; either version 2 of the License, or
  16. # (at your option) any later version.
  17. #
  18. # This program is distributed in the hope that it will be useful,
  19. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21. # GNU General Public License for more details.
  22. #
  23. # You should have received a copy of the GNU General Public License
  24. # along with this program; if not, write to the Free Software
  25. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  26.  
  27. ####################
  28. # See the usage subroutine for explanation about how the program can be called
  29. ####################
  30.  
  31. use warnings;
  32. use strict;
  33. use Getopt::Long;
  34. use Debian::AdduserCommon;
  35.  
  36. my $install_more_packages ;
  37.  
  38. BEGIN {
  39.     local $ENV{PERL_DL_NONLAZY}=1;
  40.     eval 'use File::Find';
  41.     if ($@) {
  42.       $install_more_packages = 1;
  43.     }
  44.     #no warnings "File::Find";
  45.     eval 'use File::Temp';
  46.     if ($@) {
  47.       $install_more_packages = 1;
  48.     }
  49. }
  50.  
  51.  
  52. BEGIN {
  53.     eval 'use Locale::gettext';
  54.     if ($@) {
  55.         *gettext = sub { shift };
  56.         *textdomain = sub { "" };
  57.         *LC_MESSAGES = sub { 5 };
  58.     }
  59.     eval {
  60.         require POSIX;
  61.         import POSIX qw(setlocale);
  62.     };
  63.     if ($@) {
  64.         *setlocale = sub { return 1 };
  65.     }
  66. }
  67.  
  68. setlocale(LC_MESSAGES, "");
  69. textdomain("adduser");
  70.  
  71. my $action = $0 =~ /delgroup$/ ? "delgroup" : "deluser";
  72. our $verbose = 1;
  73. my %pconfig = ();
  74. my %config = ();
  75. my $configfile;
  76. my @defaults;
  77. my $force;
  78.  
  79.  
  80. unless ( GetOptions ("quiet|q" => sub {$verbose = 0; },
  81.             "debug" => sub {$verbose = 2; },
  82.         "version|v" => sub { &version(); exit 0; },
  83.         "help|h" => sub { &usage(); exit 0;},
  84.         "group" => sub { $action = "delgroup";},
  85.         "conf=s" => \$configfile,
  86.         "system" => \$pconfig{"system"},
  87.         "only-if-empty" => \$pconfig{"only_if_empty"},
  88.         "remove-home" => \$pconfig{"remove_home"},
  89.         "remove-all-files" => \$pconfig{"remove_all_files"},
  90.         "backup" => \$pconfig{"backup"},
  91.         "backup-to=s" => \$pconfig{"backup_to"},
  92.             "force" => \$force
  93.        ) ) {
  94.     &usage;
  95.     exit 1;
  96. }
  97.  
  98. # everyone can issue "--help" and "--version", but only root can go on
  99. dief (gtx("Only root may remove a user or group from the system.\n")) if ($> != 0);
  100.  
  101. if (!defined($configfile)) { 
  102.     @defaults = ("/etc/adduser.conf", "/etc/deluser.conf");
  103. } else {
  104.     @defaults = ($configfile);
  105. }
  106.  
  107. my @names = ();
  108. my ($user,$group);
  109.  
  110. ######################
  111. # handling of @names #
  112. ######################
  113.  
  114. while (defined(my $arg = shift(@ARGV))) {
  115.   if (defined($names[0]) && $arg =~ /^--/) {
  116.       dief (gtx("No options allowed after names.\n"));
  117.     } else {            # it's a username
  118.     push (@names, $arg);
  119.     }
  120. }
  121.  
  122. if(@names == 0) {
  123.     if($action eq "delgroup") {
  124.     print (gtx("Enter a group name to remove: "));
  125.     } else {
  126.     print (gtx("Enter a user name to remove: "));
  127.     }
  128.     chomp(my $answer=<STDIN>);
  129.     push(@names, $answer);
  130. }
  131.  
  132. if (length($names[0]) == 0 || @names > 2) {
  133.     dief (gtx("Only one or two names allowed.\n"));
  134. }
  135.  
  136. if(@names == 2) {      # must be deluserfromgroup
  137.     $action = "deluserfromgroup";
  138.     $user = shift(@names);
  139.     $group = shift(@names);
  140. } else {
  141.     if($action eq "delgroup") {
  142.     $group = shift(@names);
  143.     } else {
  144.     $user = shift(@names);
  145.     }
  146. }
  147.  
  148. undef(@names);
  149.  
  150.  
  151. ##########################################################
  152. # (1) preseed the config
  153. # (2) read the default /etc/adduser.conf configuration.
  154. # (3) read the default /etc/deluser.conf configuration.
  155. # (4) process commmand line settings
  156. # last match wins
  157. ##########################################################
  158.  
  159. preseed_config (\@defaults,\%config);
  160.  
  161. foreach(keys(%pconfig)) {
  162.     $config{$_} = $pconfig{$_} if ($pconfig{$_});
  163. }
  164. undef (%pconfig);
  165.  
  166. if (($config{remove_home} || $config{remove_all_files} || $config{backup}) && ($install_more_packages)) {
  167.     fail (8, gtx("In order to use the --remove-home, --remove-all-files, and --backup features,
  168. you need to install the `perl-modules' package. To accomplish that, run
  169. apt-get install perl-modules.\n"));
  170. }
  171.  
  172.  
  173. my ($pw_uid, $pw_gid, $pw_homedir, $gr_gid, $maingroup);
  174.  
  175. if($user) {
  176.     my @passwd = getpwnam($user);
  177.     $pw_uid = $passwd[2];
  178.     $pw_gid = $passwd[3];
  179.     $pw_homedir = $passwd[7];
  180.     
  181.     $maingroup = $pw_gid ? getgrgid($pw_gid) : "";
  182. }
  183. if($group) {
  184.     #($gr_name,$gr_passwd,$gr_gid,$gr_members) = getgrnam($group);
  185.     my @group = getgrnam($group);
  186.     $gr_gid = $group[2];
  187. }
  188.  
  189. # arguments are processed:
  190. #
  191. #  $action = "deluser"
  192. #     $user          name of the user to remove
  193. #
  194. #  $action = "delgroup"
  195. #     $group         name of the group to remove
  196. #
  197. #  $action = "deluserfromgroup"
  198. #     $user          the user to be remove
  199. #     $group         the group to remove him/her from
  200.  
  201.  
  202. if($action eq "deluser") {
  203.     &invalidate_nscd();
  204.     
  205.     my($dummy1,$dummy2,$uid);
  206.  
  207.  
  208.  
  209.  
  210.  
  211.     # Don't allow a non-system user to be deleted when --system is given
  212.     # Also, "user does not exist" is only a warning with --system, but an
  213.     # error without --system.
  214.     if( $config{"system"} ) {
  215.     if( ($dummy1,$dummy2,$uid) = getpwnam($user) ) {
  216.         if ( ($uid < $config{"first_system_uid"} ||
  217.         $uid > $config{"last_system_uid" } ) ) {
  218.         printf (gtx("The user `%s' is not a system user. Exiting.\n"), $user) if $verbose;
  219.         exit 1;
  220.         }
  221.         } else {
  222.         printf (gtx("The user `%s' does not exist, but --system was given. Exiting.\n"), $user) if $verbose;
  223.         exit 0;
  224.     }
  225.     }
  226.     
  227.     unless(exist_user($user)) {
  228.     fail (2,gtx("The user `%s' does not exist.\n"),$user);
  229.     }
  230.     
  231.     # Warn in any case if you want to remove the root account 
  232.     if ((defined($pw_uid)) && ($pw_uid == 0) && (!defined($force)))  {
  233.         printf (gtx("WARNING: You are just about to delete the root account (uid 0)\n"));
  234.         printf (gtx("Usually this is never required as it may render the whole system unusable\n"));
  235.         printf (gtx("If you really want this, call deluser with parameter --force\n"));
  236.         printf (gtx("Stopping now without having performed any action\n"));
  237.         exit 9;
  238.     }
  239.  
  240.  
  241.     if($config{"remove_home"} || $config{"remove_all_files"}) {
  242.       s_print (gtx("Looking for files to backup/remove ...\n"));
  243.       my @mountpoints;
  244.       open(MOUNT, "mount |")
  245.           || fail (4 ,gtx("fork for `mount' to parse mount points failed: %s\n", $!));
  246.       while (<MOUNT>) {
  247.           my @temparray = split;
  248.           my $fstype = $temparray[4];
  249.           my $exclude_fstypes = $config{"exclude_fstypes"};
  250.           if (defined($exclude_fstypes)) {
  251.               next if ($fstype =~ /$exclude_fstypes/);
  252.           }
  253.           push @mountpoints,$temparray[2];
  254.       }
  255.       close(MOUNT) or dief (gtx("pipe of command `mount' could not be closed: %s\n",$!));
  256.       my(@files,@dirs);
  257.       if($config{"remove_home"} && ! $config{"remove_all_files"}) {
  258.  
  259.         # collect all files in user home
  260.     sub home_match {
  261.       # according to the manpage
  262.       foreach my $mount (@mountpoints) {
  263.         if( $File::Find::name eq $mount ) {
  264.           s_printf (gtx("Not backing up/removing `%s', it is a mount point.\n"),$File::Find::name);
  265.           $File::Find::prune=1;
  266.           return;
  267.         }
  268.       }
  269.       foreach my $re ( split ' ', $config{"no_del_paths"} ) {
  270.         if( $File::Find::name =~ qr/$re/ ) {
  271.           s_printf (gtx("Not backing up/removing `%s', it matches %s.\n"),$File::Find::name,$re);
  272.           $File::Find::prune=1;
  273.           return;
  274.         }
  275.       }
  276.  
  277.       push(@files, $File::Find::name) 
  278.         if(-f $File::Find::name || -l $File::Find::name);
  279.       push(@dirs, $File::Find::name)
  280.         if(-d $File::Find::name);
  281.     } # sub home_match
  282.  
  283.     # collect ecryptfs config files not stored in $HOME
  284.     sub ecryptfs_match {
  285.       if ( $File::Find::name !~ m[^/var/lib/ecryptfs/\Q$user] &&  $File::Find::name !~ m[^/home/\.ecryptfs/\Q$user]) {
  286.         $File::Find::prune=1;
  287.         return;
  288.       }
  289.       push(@files, $File::Find::name)
  290.         if(-f $File::Find::name || -l $File::Find::name);
  291.       push(@dirs, $File::Find::name)
  292.         if(-d $File::Find::name);
  293.     } # sub ecryptfs_match
  294.  
  295.     File::Find::find({wanted => \&home_match, untaint => 1, no_chdir => 1}, $pw_homedir)
  296.       if(-d "$pw_homedir");
  297.     if(-d "/var/lib/ecryptfs/$user") {
  298.       File::Find::find({wanted => \&ecryptfs_match, untaint => 1, no_chdir => 1}, "/var/lib/ecryptfs/$user");
  299.     } elsif (-d "/home/.ecryptfs/$user") {
  300.       File::Find::find({wanted => \&ecryptfs_match, untaint => 1, no_chdir => 1}, "/home/.ecryptfs/$user");
  301.     }
  302.     push(@files, "/var/mail/$user")
  303.       if(-e "/var/mail/$user");
  304.       } else {
  305.  
  306.         # collect all files on system belonging to that user
  307.     sub find_match {
  308.       my ($dev,$ino,$mode,$nlink,$uid,$gid);
  309.       (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
  310.         ($uid == $pw_uid) &&
  311.           (
  312.         ($File::Find::name =~ /^\/proc\// && ($File::Find::prune = 1)) ||
  313.         (-f $File::Find::name && push(@files, $File::Find::name)) ||
  314.         (-d $File::Find::name && push(@dirs, $File::Find::name)) ||
  315.                 (-l $File::Find::name && push(@dirs, $File::Find::name)) ||
  316.                 (-s $File::Find::name && push(@dirs, $File::Find::name)) || 
  317.                 (-p $File::Find::name && push(@dirs, $File::Find::name))
  318.           );
  319.     } # sub find_match
  320.     
  321.     File::Find::find({wanted => \&find_match, untaint => 1, no_chdir => 1}, '/');
  322.       }
  323.  
  324.       if($config{"backup"}) {
  325.      s_printf (gtx("Backing up files to be removed to %s ...\n"),$config{"backup_to"});
  326.      my $filesfile = new File::Temp(TEMPLATE=>"deluser.XXXXX", DIR=>"/tmp");
  327.      my $filesfilename = $filesfile->filename;
  328.      my $backup_name = $config{"backup_to"} . "/$user.tar";
  329.      print "backup_name = $backup_name";
  330.      print $filesfile join("\n",@files);
  331.      $filesfile->close();
  332.          my $tar = &which('tar');
  333.          my $bzip2 = &which('bzip2', 1);
  334.          my $gzip = &which('gzip', 1);
  335.          my $options = '';
  336.      if($bzip2) {
  337.              $backup_name = "$backup_name.bz2";
  338.              $options = "--bzip2";
  339.      } elsif($gzip) {
  340.              $backup_name = "$backup_name.gz";
  341.              $options = "--gzip";
  342.      }
  343.      &systemcall($tar, $options, "-cf", $backup_name, "--files-from", $filesfilename);
  344.      chmod 0600, $backup_name;
  345.          my $rootid = 0;
  346.      chown $rootid, $rootid, $backup_name;
  347.      unlink($filesfilename);
  348.       }
  349.  
  350.       if(@files || @dirs) {
  351.       s_print (gtx("Removing files ...\n"));
  352.       unlink(@files) if(@files);
  353.       foreach(reverse(sort(@dirs))) {
  354.           rmdir($_);
  355.       }
  356.       }
  357.     }
  358.  
  359.     if (system("crontab -l $user >/dev/null 2>&1") == 0) {
  360.       # crontab -l returns 1 if there is no crontab
  361.       my $crontab = &which('crontab');
  362.       &systemcall($crontab, "-r", $user);
  363.       s_print (gtx("Removing crontab ...\n"));
  364.     }
  365.  
  366.     s_printf (gtx("Removing user `%s' ...\n"),$user);
  367.     my @members = get_group_members($maingroup);
  368.     if (@members == 0) {
  369.         s_printf (gtx("Warning: group `%s' has no more members.\n"), $maingroup);    
  370.     }
  371.     my $userdel = &which('userdel');
  372.     &systemcall($userdel, $user);
  373.     &invalidate_nscd();
  374.  
  375.     systemcall('/usr/local/sbin/deluser.local', $user, $pw_uid,
  376.                 $pw_gid, $pw_homedir) if (-x "/usr/local/sbin/deluser.local");
  377.  
  378.     s_print (gtx("Done.\n"));
  379.     exit 0;
  380. }
  381.  
  382.     
  383. if($action eq "delgroup") {
  384.     &invalidate_nscd();
  385.     unless(exist_group($group)) {
  386.     printf( gtx("The group `%s' does not exist.\n"),$group) if $verbose;
  387.         exit 3;
  388.     }
  389.     my($dummy,$gid,$members);
  390.     if( !(($dummy, $dummy, $gid, $members ) = getgrnam($group)) ) {
  391.     fail (4 ,gtx("getgrnam `%s' failed. This shouldn't happen.\n"), $group);
  392.     }
  393.     if( $config{"system"} && 
  394.     ($gid < $config{"first_system_gid"} ||
  395.      $gid > $config{"last_system_gid" } )) {
  396.         printf (gtx("The group `%s' is not a system group. Exiting.\n"), $group) if $verbose;
  397.     exit 3;
  398.     }
  399.     if( $config{"only_if_empty"} && $members ne "") {
  400.     fail (5, gtx("The group `%s' is not empty!\n"),$group);
  401.     }
  402.     
  403.     setpwent;
  404.     while ((my $acctname,my $primgrp) = (getpwent)[0,3]) {
  405.     if( $primgrp eq $gr_gid ) {
  406.         fail (7, gtx("`%s' still has `%s' as their primary group!\n"),$acctname,$group);
  407.     }
  408.     }
  409.     endpwent;
  410.  
  411.     s_printf (gtx("Removing group `%s' ...\n"),$group);
  412.     my $groupdel = &which('groupdel');
  413.     &systemcall($groupdel,$group);
  414.     &invalidate_nscd();
  415.     s_print (gtx("Done.\n"));
  416.     exit 0;
  417. }
  418.  
  419.  
  420. if($action eq "deluserfromgroup")
  421. {
  422.     &invalidate_nscd();
  423.     unless(exist_user($user)) {
  424.     fail (2, gtx("The user `%s' does not exist.\n"),$user);
  425.     }
  426.     unless(exist_group($group)) {
  427.     fail (3, gtx("The group `%s' does not exist.\n"),$group);
  428.     }
  429.     if($maingroup eq $group) {
  430.     fail (7, gtx("You may not remove the user from their primary group.\n"));
  431.     }
  432.  
  433.     my @members = get_group_members($group);
  434.     my $ismember = 0;
  435.  
  436.     for(my $i = 0; $i <= $#members; $i++) {
  437.     if($members[$i] eq $user) {
  438.         $ismember = 1;
  439.         splice(@members,$i,1);
  440.     }
  441.     }
  442.  
  443.     unless($ismember) {
  444.     fail (6, gtx("The user `%s' is not a member of group `%s'.\n"),$user,$group);
  445.     }
  446.  
  447.     s_printf (gtx("Removing user `%s' from group `%s' ...\n"),$user,$group);
  448.     #systemcall("usermod","-G", join(",",@groups), $user );
  449.     my $gpasswd = &which('gpasswd');
  450.     &systemcall($gpasswd,'-M', join(',',@members), $group);
  451.     &invalidate_nscd();
  452.     s_print (gtx("Done.\n"));
  453. }
  454.  
  455.  
  456. ######
  457.  
  458. sub fail {
  459.   my ($errorcode, $format, @args) = @_;
  460.   printf STDERR "$0: $format",@args;
  461.   exit $errorcode;
  462.  
  463. }
  464.  
  465. sub version {
  466.     printf (gtx("deluser version %s\n\n"), $version);
  467.     printf (gtx("Removes users and groups from the system.\n"));
  468.     
  469.     printf gtx("Copyright (C) 2000 Roland Bauerschmidt <roland\@copyleft.de>\n\n");
  470.  
  471.     printf gtx("deluser is based on adduser by Guy Maor <maor\@debian.org>, Ian Murdock\n".
  472.       "<imurdock\@gnu.ai.mit.edu> and Ted Hajek <tedhajek\@boombox.micro.umn.edu>\n\n");
  473.  
  474.     printf gtx("This program is free software; you can redistribute it and/or modify
  475. it under the terms of the GNU General Public License as published by
  476. the Free Software Foundation; either version 2 of the License, or (at
  477. your option) any later version.
  478.  
  479. This program is distributed in the hope that it will be useful, but
  480. WITHOUT ANY WARRANTY; without even the implied warranty of
  481. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  482. General Public License, /usr/share/common-licenses/GPL, for more details.\n");
  483. }
  484.  
  485. sub usage {
  486.     printf gtx(
  487. "deluser USER
  488.   remove a normal user from the system
  489.   example: deluser mike
  490.  
  491.   --remove-home             remove the users home directory and mail spool
  492.   --remove-all-files        remove all files owned by user
  493.   --backup                  backup files before removing.
  494.   --backup-to <DIR>         target directory for the backups.
  495.                             Default is the current directory.
  496.   --system                  only remove if system user
  497.  
  498. delgroup GROUP
  499. deluser --group GROUP
  500.   remove a group from the system
  501.   example: deluser --group students
  502.  
  503.   --system                  only remove if system group
  504.   --only-if-empty           only remove if no members left
  505.  
  506. deluser USER GROUP
  507.   remove the user from a group
  508.   example: deluser mike students
  509.  
  510. general options:
  511.   --quiet | -q      don't give process information to stdout
  512.   --help | -h       usage message
  513.   --version | -v    version number and copyright
  514.   --conf | -c FILE  use FILE as configuration file\n\n");
  515. }
  516.  
  517. sub exist_user {
  518.     my $exist_user = shift;
  519.     return(defined getpwnam($exist_user));
  520. }
  521.  
  522. sub exist_group {
  523.     my $exist_group = shift;
  524.     return(defined getgrnam($exist_group));
  525. }
  526.  
  527. # vim:set ai et sts=4 sw=4 tw=0:
  528.